#include "messageSocket.h"
#include <QString>
#include <QNetworkInterface>
#include <QHostAddress>
#include <QByteArray>
#include <QPixmap>
#include <QBuffer>

MessageSocket::MessageSocket(const QString &uuid, QObject *parent, quint16 broadcastPort,
                             quint16 udpPort)
    :QObject(parent), m_portBroadcast(broadcastPort),
      m_portUdp(udpPort), m_uuid(uuid), m_byteArrayUuid(uuid.toUtf8())
{
    if(m_byteArrayUuid.size() != 32){
        qDebug() << "uuid.size() != 32";
        exit(1);
    }
    //UdpHead的大小避免以后反复计算
    m_udpHeadSize = sizeof(UdpHead);
    //初始化网络通信Socket
    m_socketBroadcast = new QUdpSocket(this);
    if(!m_socketBroadcast->bind(QHostAddress::AnyIPv4, m_portBroadcast)){
        qDebug() << QString("broadcastSocket->bind(%1) error!").arg(m_portBroadcast);
        exit(1);
    }

    m_socketUdp = new QUdpSocket(this);
    if(!m_socketUdp->bind(QHostAddress::AnyIPv4, m_portUdp)){
        qDebug() << QString("udpSocket->bind(%1) error!").arg(m_portUdp);
        exit(1);
    }

    //连接信息与槽
    connect(m_socketBroadcast, &QUdpSocket::readyRead, this, &MessageSocket::onSocketBroadcastReadyRead);
    connect(m_socketUdp, &QUdpSocket::readyRead, this, &MessageSocket::onSocketUdpReadyRead);
}

QHostAddress MessageSocket::getHostAddress(const QString &uuid)
{
    HostAddressMapIterator ite = m_hostAddressMap.find(uuid);
    if(ite == m_hostAddressMap.cend()){
        return QHostAddress();
    }
    return ite.value();
}

bool MessageSocket::sendLoginMessage(const QString &yourName)
{
    //把消息头放入QByteArray中
    QByteArray array;
    QByteArray name(yourName.toUtf8());
    this->setUdpHead(array, MessageTypeLogin, name.size());
    array.append(name);
    //向广播地址发送消息
    if(m_socketBroadcast->writeDatagram(array, QHostAddress::Broadcast, m_portBroadcast)
            == array.size()){
        return true;
    }
    else{
        return false;
    }
}

bool MessageSocket::sendNameMessage(const QString &yourName)
{
    QByteArray array;
    QByteArray name(yourName.toUtf8());
    this->setUdpHead(array, MessageTypeName, name.size());
    array.append(name);
    if(m_socketBroadcast->writeDatagram(array, QHostAddress::Broadcast, m_portBroadcast)
            == array.size()){
        return true;
    }
    else{
        return false;
    }
}

bool MessageSocket::sendPhotoMessage(const QPixmap &photo)
{
    return this->sendImage(m_socketBroadcast, QHostAddress::Broadcast, m_portBroadcast
                           , photo, MessageTypePhoto);
}

bool MessageSocket::sendPhotoMessage(const QString &uuid, const QPixmap &photo)
{
    HostAddressMapIterator ite = m_hostAddressMap.find(uuid);
    if(ite == m_hostAddressMap.cend()){
        qDebug() << QString("这个uuid(%1)找不到对应的ip地址").arg(uuid);
        return false;
    }
    return this->sendImage(m_socketUdp, ite.value(), m_portUdp, photo, MessageTypePhoto);
}

bool MessageSocket::sendImageMessage(const QString &uuid, const QPixmap &image)
{
    HostAddressMapIterator ite = m_hostAddressMap.find(uuid);
    if(ite == m_hostAddressMap.cend()){
        qDebug() << QString("这个uuid(%1)找不到对应的ip地址").arg(uuid);
        return false;
    }
    return this->sendImage(m_socketUdp, ite.value(), m_portUdp, image, MessageTypeImage);
}

bool MessageSocket::sendExitMessage()
{
    QByteArray array;
    this->setUdpHead(array, MessageTypeExit, 0);
    if(m_socketBroadcast->writeDatagram(array, QHostAddress::Broadcast, m_portBroadcast)
            == array.size()){
        return true;
    }
    else{
        return false;
    }
}

bool MessageSocket::sendText(const QString &friendUuid, const QString &message)
{
    HostAddressMapIterator ite = m_hostAddressMap.find(friendUuid);
    if(ite == m_hostAddressMap.cend()){
        qDebug() << QString("这个uuid(%1)找不到对应的ip地址").arg(friendUuid);
        return false;
    }
    //把消息头和消息本身填入QByterArray中
    QByteArray array;
    QByteArray msg(message.toUtf8());
    this->setUdpHead(array, MessageTypeText, msg.size());
    array.append(msg);
    //往指定IP地址发送消息
    if(m_socketUdp->writeDatagram(array.data(), array.size(), ite.value(), m_portUdp)
            == array.size()){
        return true;
    }
    else{
        return false;
    }
}

bool MessageSocket::sendEchoLoginMessage(const QString &friendUuid, const QString &name)
{
    HostAddressMapIterator ite = m_hostAddressMap.find(friendUuid);
    if(ite == m_hostAddressMap.cend()){
        qDebug() << QString("这个uuid(%1)找不到对应的ip地址").arg(friendUuid);
        return false;
    }
    //把消息头和消息本身填入QByterArray中
    QByteArray array;
    QByteArray msg(name.toUtf8());
    this->setUdpHead(array, MessageTypeEchoLogin, msg.size());
    array.append(msg);

    qDebug() << QString("EchoLogin()向ip(%1)发送(%2)")
                .arg(ite.value().toString())
                .arg(name);
    //往指定IP地址发送消息
    if(m_socketUdp->writeDatagram(array.data(), array.size(), ite.value(), m_portUdp)
            == array.size()){
        return true;
    }
    else{
        return false;
    }

}

void MessageSocket::onSocketBroadcastReadyRead()
{
    QByteArray array;
    array.resize(m_socketBroadcast->pendingDatagramSize());
    QHostAddress address;
    quint16 port;
    m_socketBroadcast->readDatagram(array.data(), array.size(), &address, &port);
    if(IsLocalhostIp(address.toString())){
        qDebug() << "收到本地消息,舍弃";
        return;
    }

    //分离消息头和消息
    UdpHead *head = (UdpHead*)array.data();
    QString uuid = getUuid(head);
    //收到的消息
    QByteArray message;
    message.append(array.data()+m_udpHeadSize, head->m_messageLength);

    switch (head->m_type) {
    case MessageTypeLogin:
        m_hostAddressMap.insert(uuid, address);
        emit hasLoginMessage(uuid, QString(message));
        break;
    case MessageTypeExit:
        emit hasExitMessage(uuid);
        break;
    case MessageTypeName:
        emit hasNameMessage(uuid, QString(message));
        break;
    case MessageTypePhoto:
    {
        int index = recvImage(uuid, message, m_friendPhotos);
        if(index > -1){
            QPixmap pixmap;
            if(!pixmap.loadFromData(m_friendPhotos.at(index).second)){
                qDebug() << "pixmap.loadFromDate() error!";
            }
            else{
                qDebug() << "已经接收完照片uuid = " << m_friendPhotos.at(index).first;
                emit hasPhotoMessage(uuid, pixmap);
            }
            m_friendPhotos.remove(index);
        }
        break;
    }
    default:
        qDebug() << QString("广播收到uuid(%1), ip(%2), port(%3)的无用消息")
                    .arg(uuid)
                    .arg(address.toString())
                    .arg(port);
        break;
    }
}

void MessageSocket::onSocketUdpReadyRead()
{
    QByteArray array;
    QHostAddress addr;
    quint16 port;
    array.resize(m_socketUdp->pendingDatagramSize());
    if(m_socketUdp->readDatagram(array.data(), array.size(), &addr, &port) != array.size()){
        qDebug() << "读取socketUdp错误";
        return;
    }
    //获取消息头
    QByteArray headArray = array.left(m_udpHeadSize);
    UdpHead *head = (UdpHead*)headArray.data();
    if(array.size() != head->m_messageLength + m_udpHeadSize){
        qDebug() << "读取socketUdp错误";
        return;
    }
    QString uuid = getUuid(head);
    QByteArray messageArray = array.right(head->m_messageLength);
    switch (head->m_type) {
    case MessageTypeEchoLogin:
        m_hostAddressMap.insert(uuid, addr);
        emit hasEchoLoginMessage(uuid, QString(messageArray));
        break;
    case MessageTypeText:
        emit hasTextMessage(uuid, QString(messageArray));
        break;
    case MessageTypePhoto:
    {
        int index = recvImage(uuid, messageArray, m_friendPhotos);
        if(index > -1){
            QPixmap pixmap;
            if(!pixmap.loadFromData(m_friendPhotos.at(index).second)){
                qDebug() << "pixmap.loadFromDate() error!";
            }
            else{
                qDebug() << "已经接收完照片uuid = " << m_friendPhotos.at(index).first;
                emit hasPhotoMessage(uuid, pixmap);
            }
            m_friendPhotos.remove(index);
        }
    }
        break;
    case MessageTypeImage:
    {
        int index = recvImage(uuid, messageArray, m_friendImages);
        if(index > -1){
            QImage image;
            if(!image.loadFromData(m_friendImages.at(index).second)){
                qDebug() << "image.loadFromDate() error!";
            }
            else{
                qDebug() << "已经接收完图片uuid = " << m_friendImages.at(index).first;
                emit hasImageMessage(uuid, image);
            }
            m_friendImages.remove(index);
        }
    }
        break;
    default:
        qDebug() << QString("单播uuid(%1), ip(%2), port(%3)的无用消息")
                    .arg(QString(uuid))
                    .arg(addr.toString())
                    .arg(port);
        break;
    }
}

bool MessageSocket::sendImage(QUdpSocket *socket, QHostAddress addr, quint16 port,
                              const QPixmap &pixMap, MessageSocket::MessageType messageType)
{
    //把图片保存到QByteArray中
    QByteArray bufferArray;
    QBuffer buffer(&bufferArray);
    if(!buffer.open(QIODevice::ReadWrite)){
        qDebug() << "sendImage() 错误! buf.open()失败!";
        return false;
    }
    if(!pixMap.save(&buffer, "JPG")){
        qDebug() << "sendImage() 错误! pixMap.save()失败!";
        return false;
    }
    buffer.seek(0);
    //开始发送照片，分成blockSize大小的包发送
    //第一个包和最后一个包只有头没有内容,用于界定照片是否收发完整
    QByteArray sendArray;
    int blockSize = 1024;
    //发送第一个包
    this->setUdpHead(sendArray, messageType, 0);
    socket->writeDatagram(sendArray, addr, port);
    //发送剩下的包
    while(1){
        sendArray.clear();
        QByteArray array = buffer.read(blockSize);
        this->setUdpHead(sendArray, messageType, array.size());
        sendArray.append(array);
        socket->writeDatagram(sendArray, addr, port);
        if(array.size() == 0){
            break;
        }
    }
    buffer.close();
    return true;
}

int MessageSocket::recvImage(const QString &uuid, const QByteArray &message, QVector<QPair<QString, QByteArray> > &saveVector)
{
    bool isFind = false;
    int index;
    for(index = 0; index != saveVector.size(); ++index){
        if(saveVector.at(index).first == uuid){
            isFind = true;
            break;
        }
    }
    if(isFind){
        if(message.size() == 0){
            return index;
        }
        else{
            qDebug() << QString("已接收uuid(%1)的 %2 的消息")
                        .arg(saveVector.at(index).first)
                        .arg(saveVector.at(index).second.size());
            saveVector[index].second.append(message);
            return -1;
        }
    }
    else{
        if(message.size() == 0){
            saveVector.push_front(QPair<QString, QByteArray>(uuid, QByteArray()));
        }
        return -1;
    }
}

bool MessageSocket::IsLocalhostIp(const QString &ip)
{
    static QList<QHostAddress> *addrList = nullptr;
    if(!addrList){
        addrList = new QList<QHostAddress>();
        *addrList = QNetworkInterface::allAddresses();
    }
    for(int i = 0; i < addrList->size(); ++i){
        if(addrList->at(i).toString() == ip){
            return true;
        }
    }
    return false;
}

void MessageSocket::setUdpHead(QByteArray &array, MessageSocket::MessageType type, int messageSize)
{
    UdpHead udpHead;
    udpHead.m_type = type;
    udpHead.m_messageLength = messageSize;
    for(int i = 0; i < 32 ; ++i){
        udpHead.m_uuid[i] = m_byteArrayUuid.at(i);
    }
    array.append((char*)&udpHead, m_udpHeadSize);
}

QString MessageSocket::getUuid(const MessageSocket::UdpHead *head)
{
    QByteArray array;
    array.append(head->m_uuid, 32);
    return QString(array);
}
